﻿/**
* @fileOverview This file has functions related to the developing of all the functions and the 
* objects needed to communicate with the WebService, that the game developer will need.
* @author <a href="mailto:massimiliano.bertolucci@gmail.com">Massimiliano Bertolucci</a>
* @author <a href="mailto:b.giacomo@gmail.com">Giacomo Bosio</a>
* @author <a href="mailto:diana@cli.di.unipi.it">Nicholas Diana</a>
* @author <a href="mailto:peppepausa@gmail.com">Giuseppe Sollano</a>
* @version 1.0.1
*/

function IllegalArgumentException() {
    Error.apply(this, arguments);
}

IllegalArgumentException.prototype = new Error();
IllegalArgumentException.prototype.constructor = IllegalArgumentException;
IllegalArgumentException.prototype.name = 'IllegalArgumentException';

function ConnectException() {
    Error.apply(this, arguments);
}

ConnectException.prototype = new Error();
ConnectException.prototype.constructor = ConnectException;
ConnectException.prototype.name = 'ConnectException';

/**
* Necessary data structure for the developing of the login module
* @name loginData
* @public 
* @param {String} nick nickname
* @param {String} pass password
*
*/
function loginData(nick, pass) {
    this.nickname = nick;
    this.password = pass;
}

/**
* Login data structure
* @private
* @name logoutData
*/
function logoutData(userid) {
    this.connectionSuccess;
    this.userid = userid;
}

/**
* Data structure for the User's registration data exchange between WebService and Client 
* Has 5 fields, representing respectively the nickname, first name, last name, email and password 
*
* @name messageRegister
* @public
* @constructor
* this {messageRegister}
*/
function messageRegister( nick, nome, cognome, email, pass) {
    //{nickname:nick,firstname:nome,lastname:cognome,email:mail,password:pass}
    this.nickname = nick;
    this.firstname = nome;
    this.lastname = cognome;
    this.email = email;
    this.password = pass;
}

/**
* Data structure for the getQuestion protocol data exchange between WebService and Client 
* Has 6 fields, representing respectively the text, question id, game level, document array, 
* subclass to eventually define the question subtype and a gameover variable
* @name messageQuestion
* @public
* @constructor
* this {messageQuestion}
*/
function messageQuestion(text, questionid, level, idocument, subclass, gameover) {
    this.text = text; //text
    this.questionid = questionid; //id question
    this.level = level; //level game
    this.idocument = idocument; //array document
    this.subclass = subclass; //json subclass define to development game
    this.gameOver = gameover; //bha
}

/**
* 
* @name tagQuestion
* @public
* @constructor
* @this {tagQuestion}
*/
function tagQuestion() {
    
}

/**
*
* Data structure that wraps up the actual score of the user
* @name messageAnswer
* @public
* @constructor
* @this {messageAnswer}
*/
function messageAnswer(score, gameover) {
    this.score = score;
    this.gameOver = gameover;
}

function GameOver(str) {
    this.txt = str;
}

function msgStat(Ahistogram) { 
    this.histogram = Ahistogram;
}

var webMethodStat = ['GetUsersPerDayHistogram'];


/**
* Creates an instance of WebService, which is the main Object responsable for all the Client side
* communications with our Web Service. Its methods expose to the game developer all of 
* the abstractions needed for the Ajax communications with the Server. 
* @name WebService
* @public
* @constructor
* @this {WebService}
* @param {String} webservice The URL of our webservice.
* @throws {IllegalArgumentException} if Url Server is not valid
*/
function WebService(webserver) {
    this.that = this;
    this.async = true;
        
    if (typeof( webserver ) == "string")
        this.webserver = webserver;
    else {throw new Error("Url server not valid");}
    /**
	* @private
    * @description Checks the object type
    * @param{Object} obj the Object to check
    * @returns {String} 
    */
    typeOf = function(obj) {
        if (typeof (obj) == 'object') {
            if (obj.length != undefined)
                return 'array';
            else if (obj instanceof loginData)
                return 'loginData';
            else if (obj instanceof messageRegister)
                return 'register';
            else return 'object';
        } else return typeof (obj);
    }
    /**
    *  
    * @private
    * @description Converts every tyoe of Client-WebService exchangeble data into a  JSON String
    * @param {Array} myArray data to convert
    * @returns {String} jsondata if myArray is a valid input
    * @returns {Array} myArray if the input is not valid
    */
    getArraytoJson = function(myArray) {
        var type = typeOf(myArray);
        if (type == 'array') {
            if (myArray.length < 0) return myArray;
            var jsondata = '{';
            var flatArray = [];
            var iter = IteratorArray(myArray);
            try {
                var item;
                if (iter.hasNext()) {
                    item = iter.next();
                    jsondata += '\"' + item.key + '\":\"' + item.value + '\"';
                }
                while (iter.hasNext()) {
                    item = iter.next();
                    jsondata += ',\"' + item.key + '\":\"' + item.value + '\"';
                }
            }
            catch (err) {
                if (err instanceof StopIteration);
            };
            //            for (var i in myArray) {//old
            //                flatArray.push({ key: i, value: myArray[i] });
            //            }
            //            jsondata += '\"' + flatArray[0].key + '\":\"' + flatArray[0].value + '\"';
            //            for (var i = 1, n = flatArray.length; i < n; ++i) {
            //                if ((flatArray[i].key !== "add") && (flatArray[i].key !== "clone"))
            //                    jsondata += ',\"' + flatArray[i].key + '\":\"' + flatArray[i].value + '\"';
            //            }
            jsondata += '}';
            return jsondata;
        } else if (type == 'loginData') {
            return '{"login":\'{"nickname":' + myArray.nickname + ',"password":"' + myArray.password + '"}\'}';
        } else if (type == 'register') {
            return '{"registerstring":\'{"nickname":"' + myArray.nickname + '","firstname":"' + myArray.firstname +
                '","lastname":"' + myArray.lastname + '","email":"' + myArray.email +
                '","password":"' + myArray.password + '"}\'}';
        }
        return myArray;
    }
    
}

WebService.prototype = {

    /**
    *
    * @public
    * @description sets the Async communication described in the WebService
    *
    */
    setAsync: function(bool) {
        this.async = bool;
    },

    AjaxSucceeded: function(result) {
        alert(result.d);
    },

    AjaxFailed: function(result) {
        alert(result.status + ' ' + result.statusText);
    },
    /**
    * This function estabilishes the Ajax connection with the WebService, with two callback 
    * functions, each one related with the positive or negative response of the communication. 
    * 
    * @public

	* @description This function estabilishes the Ajax connection with the WebService, with two callback 
    * functions, each one related with the positive or negative response of the communication. 
 	* @param {String} server the server Url
    * @param {String} par the communication parameters
    * @param {function} succCallback the communication success function
    * @param {function} errCallback the communication error function
    */
    communication: function(server, par, succCallback, errCallback) {
        var that = this;
        $.ajax({//async: this.async;
            async: this.async,
            type: "POST",
            url: server,
            data: par.toString(),
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            success: function(msg) {
                //that.AjaxSucceeded(msg);
                succCallback(msg);
            },
            error: function(msg) {
                //that.AjaxFailed(msg);
                errCallback(msg);
            }
        });
    },
    /**
    * 
    * @public 

	* @description This function uses the communication function to send the User Login parameters to the server 
    * @param {Object} datain the login parameters
    * @param {Object} dataout parameter
    * @param {function} fun function for the failed login case
    * @throws {IllegalArgumentException} if datain or dataout is not valid
    * @throws {ConnectException} if somethig goes wrong during the connection with the WebService
    */
    Login: function Login(datain, dataout, fun) {
        if (!((datain != undefined) && (datain instanceof loginData))) throw new IllegalArgumentException('datain not valid');
        if (!((dataout != undefined) && (dataout instanceof logoutData))) throw new IllegalArgumentException('dataout not valid');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver.concat('/Login');
        var dati = getArraytoJson(datain);
        if (typeof (dati) != 'string') throw new IllegalArgumentException('data not valid');
        //alert(dati);
        this.communication(
            server,
            dati,
            function(msg) {
                var mymsg = jQuery.parseJSON(msg.d);
                if (msg) {
                    if (mymsg.risposta === "true") {
                        dataout.connectionSuccess = true;
                        dataout.userid = mymsg.userid;
                        dataout.logged = false;
                        if (mymsg.logged != undefined && mymsg.logged != "")
                            dataout.logged = mymsg.logged;
                        callback();
                    } else {
                        dataout.connectionSuccess = false;
                        callback();
                    }
                } else {
                    dataout.connectionSuccess = false;
                    dataout.error = mymsg.msgerror;
                    callback();
                }
            },
            function(msg) {
                throw new ConnectException('Errore di comunicazione');
                /* alert('error'); */
            }
        );
    },
    /**
    * 
    * @public 
    * @description This function uses the communication function to send data input to the Webservice and retrieve
    * the correspondent output for the actual question instance wrapped in the messageQuestion Object
    * @param {Array} data the array data that contains the JSON message to send
    * @param {function} fun callback function
    * @param {Object} obj contains all the parameters of the game instance
    * @throws {IllegalArgumentException} if obj is not defined or if data is not valid
    * @throws {ConnectException} if somethig goes wrong during the connection with the WebService
    * datain nome gioco = string
    */
    GetQuestion: function(namegame, dataout, fun) {
        if (!((dataout != undefined) && (dataout instanceof messageQuestion))) throw new IllegalArgumentException('dataout not valid');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver.concat('/GetQuestion');
        var ar = new Array();
        ar['gamename'] = '' + namegame;
        var dati = getArraytoJson(ar);
        if (typeof (dati) != 'string') throw new IllegalArgumentException('gamename not valid');
        //alert(dati);
        this.communication(
            server,
            dati,
            function(msg) {
                var mymsg = jQuery.parseJSON(msg.d);
                if (msg) {
                    if (mymsg.risposta === "true") {
                        //alert("comunication.success.true :" + mymsg.risposta);
                        var question = jQuery.parseJSON(mymsg.question);
                        with (question) {
                            dataout.text = text;
                            dataout.questionid = questionid;
                            dataout.level = level;
                            dataout.idocument = idocument;
                            dataout.answer = answer;
                            dataout.subclass = subclass;
                        }
                        callback();
                    } else {
                        //alert('GameOver');
                        dataout.gameover = mymsg.gameover;
                        dataout.terminated = mymsg.terminated;
                        dataout.msg = new GameOver('Complimenti hai finito il gioco ');
                        callback();
                    }
                }
            },
            function(msg) {
                alert('errore');
                throw new ConnectException('Errore di comunicazione');
            }
        );
    },
    /**
    * Uses the communication function to send the instance answer to the WebService and retrieve 
    * the score wrapped up in a messageAnswer object
    * 
    * @public
    * @description Uses the communication function to send the instance answer to the WebService and retrieve 
    * the score wrapped up in a messageAnswer object
    * @param {Object} datain
    * @param {Object} dataout
 	* @param {function} fun callback function
    * @param {function} fun function for the failed login case
    * @throws {IllegalArgumentException} if datain or dataout is not valid
    * @throws {ConnectException} if somethig goes wrong during the connection with the WebService
    */
    CheckAnswer: function(namegame, datain, dataout, fun) {
        if (!((dataout != undefined) && (dataout instanceof messageAnswer))) throw new IllegalArgumentException('dataout not valid');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver.concat('/CheckAnswer');
        var ar = new Array();
        var dati;
        ar['gamename'] = '' + namegame;

        if (typeof (datain) == "string") {
            ar['answer'] = '' + datain;
            dati = getArraytoJson(ar);
        } else {
            dati = getArraytoJson(ar.concat(datain));
        }
        if (typeof (dati) != 'string') throw new IllegalArgumentException('data not valid');
        var dt = '{"answerstring":\'' + dati.toString() + '\'}';
        //var t = '{"answerstring":\'{"answer":"prova","gamename":"TagImage"}\'}';
        //alert(dt);
        this.communication(
                server,
                dt,
                function(msg) {
                    var mymsg = jQuery.parseJSON(msg.d);
                    if (msg) {
                        if (mymsg.risposta === "true") {
                            //alert("comunication.success.true :" + mymsg.risposta);
                            dataout.score = mymsg.score;
                            callback();
                        } else {//non so se va bene
                            dataout.gameover = mymsg.gameover;
                            dataout.terminated = mymsg.terminated;
                            dataout.msg = new GameOver('Complimenti hai finito il gioco ');
                            callback();
                        }
                    }
                },
                function(msg) {
                    alert('errore');
                    throw new ConnectException('Errore di comunicazione');
                }
            );
    },
    /**
    * 
    * @public
    * @description This function sends the Registration parameters to the WebService
    *     
    * @param datain {String} matches the registration json string 
    * @param fun {Function} function associated to the Server response
    * @throws {IllegalArgumentException} if there's an error on the registration parameters
    * @throws {ConnectException} if there's an error during the connection with the Webservice
    */
    Register: function(datain, dataout, fun) {
        if (!((datain != undefined) && (datain instanceof messageRegister))) throw new IllegalArgumentException('datain not valid');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver.concat('/Register');
        var data = getArraytoJson(datain);
        if (typeof (data) != 'string') throw new IllegalArgumentException('Error occur in datain');
        //alert(data);
        this.communication(
            server,
            data,
            function(msg) {
                var mymsg = jQuery.parseJSON(msg.d);
                if (msg) {
                    if (mymsg.risposta === "true") {
                        dataout.risposta = "true";
                        dataout.msg = true;
                        callback();
                    } else {
                        dataout.risposta = "false";
                        dataout.msg = mymsg.msg;
                        callback();
                    }
                }
            },
            function(msg) {
                alert('errore');
                throw new ConnectException('Errore di connssione');
            }
        );
    },

    /**
    *
    * @public
    * @description retrieves the actual score from the WebService by sending the User id 
    * to the webService and getting back his score
    * @param datain {String} match the string json {key:value}.
    * @param dataout {messageAnswer} reference argument return, match an integer for the score. 
    * @param {Function} [fun = "function(){}"] the function associated at response the server.
    * @throws {IllegalArgumentException} If the param datain is not string
    * @throws {IllegalArgumentException} If the param dataout is not the messageAnswer object.
    * @throws {ConnectException} If occur the error with the server.
    *
    */
    GetScore: function(datain, dataout, fun) {
        if (typeof (datain) != 'string') throw new IllegalArgumentException('datain not valid');
        if (!((dataout != undefined) && (dataout instanceof messageAnswer))) throw new IllegalArgumentException('dataout not valid');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver.concat('/GetScore');
        var data = '{\"gamename\":\''.concat(datain).concat('\'}');
        if (typeof (datain) != 'string') return;
        this.communication(
            server,
            data,
            function(msg) {
                var mymsg = jQuery.parseJSON(msg.d);
                if (msg) {
                    if (mymsg.risposta === "true") {
                        //alert("comunication.success.true :" + mymsg.risposta);
                        dataout.score = parseInt(mymsg.score);
                        callback();
                    } else {//non so se va bene
                        dataout.gameOver = new GameOver('Complimenti hai finito il gioco ');
                        callback();
                    }
                }
            },
            function(msg) {
                throw new ConnectException('Errore di comunicazione');
                callback();
            }
        );
    },

    /**
    * 
    * 
    * @public
    * @description sends a Logout message to the WebService
    * @throws {ConnectException} If occur the error with the server.
    *
    */
    Logout: function() {
        var server = this.webserver.concat('/Logout');
        this.communication(
            server, //server
            '{}', //data
            function() { /*alert('ok');*/ },
            function() {
                alert('error');
                throw new ConnectException('Errore di comunicazione');
            }
        );
    },

    /**
    *
    * @public 
    <p> public method of the WebService object.</p></br>
        
    <p>Invoke the generic method <i>"Statistic"</i> of the Web Service defined in object WebService.</p>
    * @throws {ConnectException} If occur the error with the server.
    * @param startdate {Date} start statistic date.
    * @param enddate {Date} end statistic date.
    * @param stat {msgStat} reference argument return, match an Array for the statistic.
    * @param webmethod {String} name webmethod used.
    * @param {Function} [fun = "function(){}"] the function associated at response the server.
    * @throws {IllegalArgumentException} If the param startdate is not a Date.
    * @throws {IllegalArgumentException} If the param enddate is not a Date.
    * @throws {IllegalArgumentException} If the param stat is not a msgStat.
    * @throws {IllegalArgumentException} If the param fun is not the function.
    * @throws {ConnectException} If occur the error with the server.
    *
    */
    Histogram: function(startdate, enddate, stat, webmethod, fun) {
        //controllo devono essere Date
        if ((startdate == undefined) || !(startdate instanceof Date)) throw new IllegalArgumentException('Errore parametro non valido');
        if ((enddate == undefined) || !(enddate instanceof Date)) throw new IllegalArgumentException('Errore parametro non valido');
        if ((stat == undefined) || !(stat instanceof msgStat)) throw new IllegalArgumentException('Errore parametro non valido');
        var callback = ((typeof (fun) != 'undefined') && (typeof (fun) == 'function')) ? fun : function() { };
        var server = this.webserver + '/' + webmethod.toString();
        //var server = this.webserver.concat('/GetUsersPerDayHistogram');
        var json = '{"intervals":\'';
        json += '{"start":"' + startdate.getDate() + '/' + (1 + startdate.getMonth()) + '/' + startdate.getFullYear();
        json += '","end":"' + enddate.getDate() + '/' + (1 + enddate.getMonth()) + '/' + enddate.getFullYear() + '"}\'}';
        //alert(json);
        this.communication(
            server,
            json,
            function(msg) {
                var mymsg = jQuery.parseJSON(msg.d);
                if (msg) {
                    if (mymsg.risposta === "true") {
                        stat.histogram = mymsg.histogram;
                        callback();
                    } else {
                        stat.histogram = [];
                        callback();
                    }
                }
            },
            function(msg) {
                alert('error');
                throw new ConnectException('Errore di comunicazione');
                callback();
            }
        );
    }

}



// alert( readCookie("myCookie") );
function readCookie(name) {
    var cookieValue = "";
    var search = name + "=";
    if (document.cookie.length > 0) {
        offset = document.cookie.indexOf(search);
        if (offset != -1) {
            offset += search.length;
            end = document.cookie.indexOf(";", offset);
            if (end == -1) end = document.cookie.length;
            cookieValue = unescape(document.cookie.substring(offset, end));
        }
    }
    return cookieValue;
}

// Example:
// writeCookie("myCookie", "my name", 24);
// Stores the string "my name" in the cookie "myCookie" which expires after 24 hours.
function writeCookie(name, value, hours) {
    var expire = "";
    if (hours != null) {
        expire = new Date((new Date()).getTime() + hours * 3600000);
        expire = "; expires=" + expire.toGMTString();
    }
    document.cookie = name + "=" + escape(value) + expire;
}

